package com.hxh.generater.springBoot.simple.gen.crud;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import com.hxh.config.Constants;
import com.hxh.entity.Project;
import com.hxh.entity.ProjectTableFiledConfig;
import com.hxh.entity.po.ClassInfo;
import com.hxh.entity.po.FieldName;
import com.hxh.generater.springBoot.util.ProcessWriteLine;
import com.hxh.util.Common;
import com.hxh.util.GenUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @ProjectName: AICode
 * @Package: com.hxh.generater
 * @Author: HXH
 * @Description:
 * @Date: 2023/11/28 15:08
 */
@Slf4j
public class GenEntity {
    /**
     * 敏感词 如password，序列化时会忽略，也就是说不返回前端
     **/
    private static final List<String> SENSITIVE_WORDS = new ArrayList<>();

    static {
        SENSITIVE_WORDS.add("password");
    }

    public static void generationOneEntity(Project project, ClassInfo classInfo) throws IOException {
        generationEntityClass(project, classInfo, null);
        generationEntityInputClass(project, classInfo, null);
        generationOneEntityMappingClass(project, classInfo);
    }

    public static String generationEntityClass(String packageName, ClassInfo classInfo) throws IOException {
        return generationEntityClass(null, classInfo, packageName);
    }

    public static String generationEntityInputClass(String packageName, ClassInfo classInfo) {
        return generationEntityInputClass(null, classInfo, packageName);
    }

    /**
     * @param project:
     * @param classInfo:
     * @return void
     * @author HXH
     * @description: 生成实体类
     * @date 2024/5/21
     **/
    private static String generationEntityClass(Project project, ClassInfo classInfo, String packageName) throws IOException {
        if (project == null && StringUtils.isBlank(packageName)) {
            log.error("generationEntityClass中，project参数和packageName参数不能同时为空!");
            throw new RuntimeException("generationEntityClass中，project参数和packageName参数不能同时为空!");
        }
        boolean returnModel = false;
        if (project == null) {
            returnModel = true;
        }

        String className = classInfo.getClassName();
        String classDesc = classInfo.getDesc();

        StringBuilder importAddition = new StringBuilder();
        StringBuilder fieldDetail = new StringBuilder();

        boolean needImportJSONField = false;
        boolean hasSensitive = false;
        List<FieldName> fieldNames = classInfo.getFieldNameList();

        for (FieldName fieldName : fieldNames) {
            ProjectTableFiledConfig projectTableFiledConfig = fieldName.getProjectTableFiledConfig();

            fieldDetail.append("    /**\n");
            fieldDetail.append("     * " + Common.getStringNotNull(fieldName.getDesc(), "").replaceAll("\\r?\\n", " ") + "\n");
            if (StringUtils.isNotBlank(fieldName.getKey())) {
                fieldDetail.append("     * 索引:" + fieldName.getKey() + "\n");
            }
            fieldDetail.append("     **/\n");
            if ("java.util.Date".equals(fieldName.getJavaType())) {
                needImportJSONField = true;
                String formatStr = "yyyy-MM-dd HH:mm:ss";
                if (projectTableFiledConfig != null) {
                    String showType = projectTableFiledConfig.getShowType();
                    String showTypeLowerCase = showType.toLowerCase();
                    if (showTypeLowerCase.contains("date")) {
                        formatStr = "yyyy-MM-dd";
                    }
                    if (showTypeLowerCase.contains("time")) {
                        formatStr = "HH:mm:ss";
                    }
                    if (showTypeLowerCase.contains("datetime")) {
                        formatStr = "yyyy-MM-dd HH:mm:ss";
                    }
                }
                fieldDetail.append("    @JsonFormat(pattern = \"" + formatStr + "\", timezone = \"GMT+8\")\n");
                fieldDetail.append("    @DateTimeFormat(pattern = \"" + formatStr + "\")\n");
            }
            if (SENSITIVE_WORDS.contains(fieldName.getJavaName())) {
                fieldDetail.append("    @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)\n");
                hasSensitive = true;
            }
            fieldDetail.append("    private " + fieldName.getJavaType() + " " + fieldName.getJavaName() + ";\n\n");

            if (projectTableFiledConfig != null) {
//                    类型: text, textarea, number, radio, checkbox, date,dateTime, file, img,association(一对一),collection(一对多)
                if ("association".equals(projectTableFiledConfig.getShowType())) {
                    //新增一个对象字段
                    String associationTable = projectTableFiledConfig.getAssociationTable();
                    JSONObject jsonObject = new JSONObject(associationTable);
                    String aTableName = jsonObject.getStr("table");
                    aTableName = StrUtil.toCamelCase(aTableName);
                    String aTableNameClassName = StrUtil.upperFirst(aTableName);
                    fieldDetail.append("    #重复校验#private " + aTableNameClassName + " " + aTableName + ";\n");
                } else if ("collection".equals(projectTableFiledConfig.getShowType())) {
                    String collectionTable = projectTableFiledConfig.getCollectionTable();
                    JSONObject jsonObject = new JSONObject(collectionTable);
                    String collectionShowType = jsonObject.getStr("showType");
                    if ("data".equals(collectionShowType)) {
                        String aTableName = jsonObject.getStr("table");
                        aTableName = StrUtil.toCamelCase(aTableName);
                        String aTableNameClassName = StrUtil.upperFirst(aTableName);
                        fieldDetail.append("    #重复校验#private List<" + aTableNameClassName + "> " + aTableName + "List;\n");
                        importAddition.append("import java.util.List;\n");
                    }
                }
            }
        }

        if (needImportJSONField) {
            importAddition.append("import com.fasterxml.jackson.annotation.JsonFormat;\n");
            importAddition.append("import org.springframework.format.annotation.DateTimeFormat;\n");
        }
        if (hasSensitive) {
            importAddition.append("import com.fasterxml.jackson.annotation.JsonProperty;\n");
        }

        File tempClassFile;
        String classNameTempName = className + ".Template";
        if (returnModel) {
            tempClassFile = File.createTempFile(className, ".Template");
        } else {
            tempClassFile = GenUtil.newFile(project, "entity", classNameTempName);
        }
        try {
            FileWriter fileWriter = new FileWriter(tempClassFile);
            BufferedWriter writer = new BufferedWriter(fileWriter);

            File template = new File(Constants.templatePathPrefix + "simple\\template\\entity\\entity");
            BufferedReader br = new BufferedReader(new FileReader(template));
            String line;
            while ((line = br.readLine()) != null) {
                if (StringUtils.isNotBlank(line)) {
                    writer.write(line);
                }
                writer.newLine();
            }
            br.close();

            //加上addition\\controllerTemplateSplit文件下，与类名相同的文件夹下所有的文件，如addition\\controllerTemplateSplit\\BatchImportExportConfigController\\addition
            File additionFile = new File(Constants.templatePathPrefix + "simple\\template\\addition\\entityTemplateAddition\\" + className);
            if (additionFile.exists() && additionFile.isDirectory()) {
                File[] additionFiles = additionFile.listFiles();
                if (additionFiles != null && additionFiles.length > 0) {
                    for (File file : additionFiles) {
                        br = new BufferedReader(new FileReader(file));
                        while ((line = br.readLine()) != null) {
                            ProcessWriteLine.processPerLine(line, importAddition, null, writer);
                        }
                        br.close();
                    }
                }
            }

            writer.newLine();
            writer.write("}");

            writer.close();
            fileWriter.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

        try {
            BufferedWriter writer;
            FileWriter fileWriter = null;
            StringWriter stringWriter = null;
            if (returnModel) {
                stringWriter = new StringWriter();
                writer = new BufferedWriter(stringWriter);
            } else {
                File classFile = GenUtil.newFile(project, "entity", className);
                fileWriter = new FileWriter(classFile);
                writer = new BufferedWriter(fileWriter);
            }

            File template = tempClassFile;
            BufferedReader br = new BufferedReader(new FileReader(template));

            String line;

            Map<String, String> replaceWord = new HashMap<>();
            replaceWord.put("importAddition", importAddition.toString());
            replaceWord.put("classDesc", classDesc);
            replaceWord.put("fieldDetail", fieldDetail.toString());
            replaceWord.put("GroupId", returnModel ? packageName : project.getBackendProject().getProjectGroup());
            replaceWord.put("className", className);
            ProcessWriteLine processWriteLine = new ProcessWriteLine(replaceWord);

            while ((line = br.readLine()) != null) {
                processWriteLine.writeLine(line, writer);
            }
            br.close();

            writer.close();
            if (fileWriter != null) {
                fileWriter.close();
            }

            String bakPath = tempClassFile.getAbsolutePath() + ".bak";
            File bakFile = new File(bakPath);
            if (tempClassFile.exists()) {
                tempClassFile.delete();
            }
            if (bakFile.exists()) {
                bakFile.delete();
            }

            if (returnModel) {
                return stringWriter.toString();
            }

        } catch (IOException e) {
            log.error("生成实体类失败", e);
        }
        return null;
    }

    /**
     * @param project:
     * @param classInfo:
     * @return void
     * @author HXH
     * @description: 生成实体类的input对象代码
     * @date 2024/5/21
     **/
    private static String generationEntityInputClass(Project project, ClassInfo classInfo, String packageName) {
        if (project == null && StringUtils.isBlank(packageName)) {
            log.error("generationEntityInputClass中，project参数和packageName参数不能同时为空!");
            throw new RuntimeException("generationEntityInputClass中，project参数和packageName参数不能同时为空!");
        }
        boolean returnModel = false;
        if (project == null) {
            returnModel = true;
        }

        String className = classInfo.getClassName() + "Input";
        String classDesc = classInfo.getDesc();

        StringBuilder importAddition = new StringBuilder();
        StringBuilder fieldDetail = new StringBuilder();

        boolean needImportJSONField = false;
        boolean hasSensitive = false;
        List<FieldName> fieldNames = classInfo.getFieldNameList();

        for (FieldName fieldName : fieldNames) {
            ProjectTableFiledConfig projectTableFiledConfig = fieldName.getProjectTableFiledConfig();

            fieldDetail.append("    /**\n");
            fieldDetail.append("     * " + Common.getStringNotNull(fieldName.getDesc(), "").replaceAll("\\r?\\n", " ") + "\n");
            if (StringUtils.isNotBlank(fieldName.getKey())) {
                fieldDetail.append("     * 索引:" + fieldName.getKey() + "\n");
            }
            fieldDetail.append("     **/\n");
            if ("java.util.Date".equals(fieldName.getJavaType())) {
                needImportJSONField = true;
                String formatStr = "yyyy-MM-dd HH:mm:ss";
                if (projectTableFiledConfig != null) {
                    String showType = projectTableFiledConfig.getShowType();
                    String showTypeLowerCase = showType.toLowerCase();
                    if (showTypeLowerCase.contains("date")) {
                        formatStr = "yyyy-MM-dd";
                    }
                    if (showTypeLowerCase.contains("time")) {
                        formatStr = "HH:mm:ss";
                    }
                    if (showTypeLowerCase.contains("datetime")) {
                        formatStr = "yyyy-MM-dd HH:mm:ss";
                    }
                }
                fieldDetail.append("    @JsonFormat(pattern = \"" + formatStr + "\", timezone = \"GMT+8\")\n");
                fieldDetail.append("    @DateTimeFormat(pattern = \"" + formatStr + "\")\n");
            }
            if (SENSITIVE_WORDS.contains(fieldName.getJavaName())) {
                fieldDetail.append("    @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)\n");
                hasSensitive = true;
            }
            fieldDetail.append("    private " + fieldName.getJavaType() + " " + fieldName.getJavaName() + ";\n\n");
        }

        if (needImportJSONField) {
            importAddition.append("import com.fasterxml.jackson.annotation.JsonFormat;\n");
            importAddition.append("import org.springframework.format.annotation.DateTimeFormat;\n");
        }
        if (hasSensitive) {
            importAddition.append("import com.fasterxml.jackson.annotation.JsonProperty;\n");
        }

        try {
            BufferedWriter writer;
            FileWriter fileWriter = null;
            StringWriter stringWriter = null;
            if (returnModel) {
                stringWriter = new StringWriter();
                writer = new BufferedWriter(stringWriter);
            } else {
                File classFile = GenUtil.newFile(project, "entity\\input", className);
                fileWriter = new FileWriter(classFile);
                writer = new BufferedWriter(fileWriter);
            }

            File template = new File(Constants.templatePathPrefix + "simple\\template\\entity\\input\\entityInput");
            BufferedReader br = new BufferedReader(new FileReader(template));

            String line;

            Map<String, String> replaceWord = new HashMap<>();
            replaceWord.put("importAddition", importAddition.toString());
            replaceWord.put("classDesc", classDesc);
            replaceWord.put("fieldDetail", fieldDetail.toString());
            replaceWord.put("GroupId", returnModel ? packageName : project.getBackendProject().getProjectGroup());
            replaceWord.put("className", className);
            ProcessWriteLine processWriteLine = new ProcessWriteLine(replaceWord);

            while ((line = br.readLine()) != null) {
                processWriteLine.writeLine(line, writer);
            }
            br.close();
            writer.close();
            if (fileWriter != null) {
                fileWriter.close();
            }

            if (returnModel) {
                return stringWriter.toString();
            }
        } catch (IOException e) {
            log.error("生成input实体类失败", e);
        }
        return null;
    }

    public static void generationOneEntityMappingClass(Project project, ClassInfo classInfo) throws IOException {
        List<FieldName> fieldNames = classInfo.getFieldNameList();
        String className = classInfo.getClassName();
        String mappingClassName = className + "Mapping";

        File classFile = GenUtil.newFile(project, "entity\\mapping", mappingClassName);

        try {
            FileWriter fileWriter = new FileWriter(classFile);
            BufferedWriter writer = new BufferedWriter(fileWriter);

            // 在这里写入文件
            writer.write("package " + project.getBackendProject().getProjectGroup() + ".entity.mapping;");
            writer.newLine();
            writer.write("import java.util.ArrayList;");
            writer.newLine();
            writer.write("import java.util.List;");
            writer.newLine();
            writer.write("import cn.hutool.json.JSONObject;");
            writer.newLine();
            writer.newLine();
            writer.write("/**");
            writer.newLine();
            writer.write(" * " + classInfo.getDesc() + " 字段映射配置");
            writer.newLine();
            writer.write(" **/");
            writer.newLine();
            writer.write("public class " + mappingClassName + " {");
            writer.newLine();

            writer.write("    public static final String entityName = \"" + className + "\";");
            writer.newLine();
            writer.write("    public static final String tableName = \"" + classInfo.getTableName() + "\";");
            writer.newLine();
            writer.write("    public static final String tableDesc = \"" + classInfo.getDesc() + "\";");
            writer.newLine();
            writer.newLine();
            writer.write("    public static final List<JSONObject> fieldInfoList = new ArrayList<>();");
            writer.newLine();
            writer.newLine();
            writer.write("    static {");
            for (FieldName fieldName : fieldNames) {
                writer.newLine();
                String jsonName = fieldName.getJavaName() + "JsonObject";
                String radioOptionName = fieldName.getJavaName() + "RadioOption";

                writer.write("        JSONObject " + jsonName + " = new JSONObject();");
                writer.newLine();
                writer.write("        " + jsonName + ".set(\"fieldName\",\"" + fieldName.getName() + "\");");
                writer.newLine();
                writer.write("        " + jsonName + ".set(\"javaName\",\"" + fieldName.getJavaName() + "\");");
                writer.newLine();

                String showName = fieldName.getDesc();
                String type = "text";
                String showSelectOption = null;
                String associationTable = null;
                String collectionTable = null;
                ProjectTableFiledConfig pfc = fieldName.getProjectTableFiledConfig();
                if (pfc != null) {
                    String configName = pfc.getShowName();
                    showName = Common.getStringNotNull(configName, showName);
//                    类型: text, textarea, number, radio, checkbox, date,dateTime, file, img
                    type = pfc.getShowType();
                    showSelectOption = pfc.getShowSelectOption();
                    associationTable = pfc.getAssociationTable();
                    collectionTable = pfc.getCollectionTable();
                }
                showName = showName.replaceAll("\\r?\\n", " ");
                showName = showName.replaceAll("\"", "\\\\\"");
                writer.write("        " + jsonName + ".set(\"desc\",\"" + showName + "\");");
                writer.newLine();

                writer.write("        " + jsonName + ".set(\"type\",\"" + type + "\");");
                writer.newLine();
                if (StringUtils.isNotBlank(showSelectOption)) {
                    String radioOptionNameReverseName = radioOptionName + "Reverse";
                    showSelectOption = showSelectOption.replaceAll("\"", "\\\\\"");
                    writer.write("        JSONObject " + radioOptionName + " = new JSONObject(\"" + showSelectOption + "\");");
                    writer.newLine();
                    writer.write("        " + jsonName + ".set(\"radioOption\"," + radioOptionName + ");");
                    writer.newLine();
                    writer.write("        JSONObject " + radioOptionNameReverseName + " = new JSONObject();");
                    writer.newLine();
                    writer.write("        for (String key : " + radioOptionName + ".keySet()) {");
                    writer.newLine();
                    writer.write("            " + radioOptionNameReverseName + ".set(" + radioOptionName + ".getStr(key),key);");
                    writer.newLine();
                    writer.write("        }");
                    writer.newLine();
                    writer.write("        " + jsonName + ".set(\"radioOptionReverse\"," + radioOptionNameReverseName + ");");
                    writer.newLine();
                } else if (StringUtils.isNotBlank(associationTable)) {
                    String associationName = fieldName.getJavaName() + "Association";
                    associationTable = associationTable.replaceAll("\"", "\\\\\"");
                    writer.write("        JSONObject " + associationName + " = new JSONObject(\"" + associationTable + "\");");
                    writer.newLine();
                    writer.write("        " + jsonName + ".set(\"associationTable\"," + associationName + ");");
                    writer.newLine();
                } else if (StringUtils.isNotBlank(collectionTable)) {
                    String collectionName = fieldName.getJavaName() + "Collection";
                    collectionTable = collectionTable.replaceAll("\"", "\\\\\"");
                    writer.write("        JSONObject " + collectionName + " = new JSONObject(\"" + collectionTable + "\");");
                    writer.newLine();
                    writer.write("        " + jsonName + ".set(\"collectionTable\"," + collectionName + ");");
                    writer.newLine();
                }
                writer.write("        fieldInfoList.add(" + jsonName + ");");
                writer.newLine();
            }
            writer.write("    }");
            writer.newLine();
            writer.write("}");
            writer.close();
            fileWriter.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}
